﻿using System;
using System.Collections.Generic;
using System.Text;

namespace TradingPlatform
{
    public class CommMessageField
    {
        public readonly static CommMessageField Name        = new CommMessageField(16);
        public readonly static CommMessageField Type        = new CommMessageField(1);
        public readonly static CommMessageField ErrorCode   = new CommMessageField(3);

        public CommMessageField(int length)
        {
            mLength = length;
        }

        public int Length
        {
            get { return mLength; }
        }

        private int mLength;
        public String convert(String str)
        {
            if (str.Length == mLength) return str;
            else if (str.Length > mLength) return str.Substring(0, mLength);
            else return str.PadRight(mLength);
        }
    };

    public class CommField
    {
        public string StringValue
        {
            get { return mValue; }
        }
        protected string mValue;
        protected void SetValue(string value, int len)
        {
            if (value.Length == len) mValue = value;
            else if (value.Length > len) mValue = value.Substring(0, len);
            else mValue = value.PadRight(len);
        }
    }

    public class CommStrField : CommField
    {
        public static string Parse(ref string msg, int len)
        {
            string value = msg.Substring(0, len);
            msg = msg.Substring(len);
            return value;
        }
    }

    public class CommIntField : CommField
    {
        public int IntValue
        {
            get { return mIntValue; }
        }
        protected int mIntValue;
        protected void ToInt()
        {
            mIntValue = Convert.ToInt32(mValue);
        }

        public static int Parse(ref string msg, int len) {
            int value = Convert.ToInt16(msg.Substring(0, len));
            msg = msg.Substring(len);
            return value;
        }
    }

    public class CommDblField : CommField
    {
        public double DoubleValue
        {
            get { return mDblValue; }
        }
        protected double mDblValue;
        protected void ToDouble()
        {
            mDblValue = Convert.ToDouble(mValue);
        }

        public static double Parse(ref string msg, int len)
        {
            double value = Convert.ToDouble(msg.Substring(0, len));
            msg = msg.Substring(len);
            return value;
        }
    }

    public class CommTypeField : CommStrField
    {
        public static int Length = 1;

        public CommTypeField(string val)
        {
            SetValue(val, Length);
        }

        public string Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValue(value, Length);
            }
        }
    }

    public class CommErrorCodeField : CommIntField
    {
        public static int Length = 3;

        public enum Code
        {
            AllOk = 0,
            OrderLinkNotReady,
            MarketNotOpen,
            DuplicateOrderID,
            WaitForUpdateAck,
            WaitForCancelAck,
            LateCancel,
        };

        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommNameField : CommStrField
    {
        public static int Length = 16;

        public string Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValue(value, Length);
            }
        }
    }

    public class CommSymbolField : CommStrField
    {
        public static int Length = 16;
        public string Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValue(value, Length);
            }
        }
    }

    public class CommTimestamp : CommStrField
    {
        public static int Length = 9;
        public string Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValue(value, Length);
            }
        }
    }

    public class CommTextField : CommStrField
    {
        public static int Length = 64;
        public string Value
        {
            get
            {
                return mValue;
            }
            set
            {
                SetValue(value, Length);
            }
        }
    }

    public class CommFlagField : CommIntField
    {
        public static int Length = 1;
        public enum Flag
        {
            Off  = 0,
            On = 1
        }
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommSzField : CommIntField
    {
        public static int Length = 10;
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommSideField : CommIntField
    {
        public static int Length = 3;

        public enum Side
        {
            Buy = 0,
            Sell = 1
        }
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommOrderTypeField : CommIntField
    {
        public static int Length = 1;

        public enum Type
        {
            Ioc = 0,
            Lmt = 1,
            Fok = 2,
            Mkt = 3
        }
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommOrderActionField : CommIntField
    {
        public static int Length = 1;

        public enum Type
        {
            Insert = 0,
            Update = 1,
            Cancel = 2
        }
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommOrderStatusField : CommIntField
    {
        public static int Length = 2;

        public enum Status
        {
            PendingInsert = 0,
            PendingFill = 1,
            PendingUpdate = 2,
            PendingCancel = 3,
            PartialFill = 4,
            Filled = 5,
            Canceled = 6,
            RejectInsert = 7,
            RejectUpdate = 8,
            RejectCancel = 9
        }
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommOrderIDField : CommIntField
    {
        public static int Length = 8;

        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommInstrumentIndexField : CommIntField
    {
        public static int Length = 5;
        public int Value
        {
            get
            {
                return mIntValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToInt();
            }
        }
    }

    public class CommPxField : CommDblField
    {
        public static int Length = 10;
        public double Value
        {
            get
            {
                return mDblValue;
            }
            set
            {
                SetValue(value.ToString(), Length);
                ToDouble();
            }
        }
    }


    public class CommMessage
    {
        public virtual string ToPlainText() { return "AbstractCommMessage"; }
        public CommTypeField TypeField;
    }

    public class OrderMessage : CommMessage
    {
        public static string Type = "0";
        public static int Length =  CommTypeField.Length + CommSymbolField.Length + CommSzField.Length + 
                                    CommPxField.Length + CommSideField.Length + CommTimestamp.Length +
                                    CommOrderTypeField.Length + CommOrderActionField.Length + CommOrderIDField.Length;

        public CommSymbolField  SymbolField = new CommSymbolField();
        public CommPxField PriceField = new CommPxField();
        public CommSzField SizeField = new CommSzField();
        public CommSideField SideField = new CommSideField();
        public CommTimestamp TimestampField = new CommTimestamp();
        public CommOrderTypeField OrderTypeField = new CommOrderTypeField();
        public CommOrderActionField OrderActionField = new CommOrderActionField();
        public CommOrderIDField OrderIDField = new CommOrderIDField();


        public OrderMessage()
        {
            TypeField = new CommTypeField(Type);
            PriceField.Value = 0;
            SizeField.Value = 0;
            SideField.Value = 0;
            OrderIDField.Value = 0;
            TimestampField.Value = "";
        }
        public static string Format(OrderMessage msg)
        {
            return msg.TypeField.StringValue + msg.SymbolField.StringValue + msg.PriceField.StringValue + msg.SizeField.StringValue + 
                msg.SideField.StringValue + msg.TimestampField.StringValue + msg.OrderTypeField.StringValue +
                msg.OrderActionField.StringValue + msg.OrderIDField.StringValue;
        }

        public override string ToPlainText()
        {
            return SymbolField.StringValue + ":" + SideField.StringValue + " " + SizeField.StringValue + " @ " + PriceField.StringValue;
        }
    }

    public class OrderStatusMessage : CommMessage
    {
        public static string Type = "1";
        public static int Length = CommTypeField.Length + CommSymbolField.Length + CommOrderIDField.Length +
                                    CommOrderStatusField.Length + CommSzField.Length + CommPxField.Length +
                                    CommSzField.Length + CommTextField.Length + CommSzField.Length;

        public CommSymbolField SymbolField = new CommSymbolField();
        public CommOrderIDField OrderIDField = new CommOrderIDField();
        public CommOrderStatusField OrderStatusField = new CommOrderStatusField();
        public CommSzField FilledSzField = new CommSzField();
        public CommPxField FilledPxField = new CommPxField();
        public CommSzField FilledTotalSzField = new CommSzField();
        public CommSzField RemainSzField = new CommSzField();
        public CommTextField TextField = new CommTextField();



        public OrderStatusMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static bool IsType(string str)
        {
            return str.Length >= Length && str[0] == Type[0];
        }

        public static string Format(OrderStatusMessage msg)
        {
            return msg.TypeField.StringValue + msg.SymbolField.StringValue + msg.OrderIDField.StringValue + msg.OrderStatusField.StringValue +
                msg.FilledSzField.StringValue + msg.FilledPxField.StringValue + msg.FilledTotalSzField.StringValue + msg.RemainSzField.StringValue +
                msg.TextField.StringValue;
        }

        public static OrderStatusMessage Parse(ref string msg)
        {
            OrderStatusMessage state = new OrderStatusMessage();
            state.TypeField.Value = CommTypeField.Parse(ref msg, CommTypeField.Length);
            state.OrderIDField.Value = CommOrderIDField.Parse(ref msg, CommOrderIDField.Length);
            state.SymbolField.Value = CommSymbolField.Parse(ref msg, CommSymbolField.Length);
            state.OrderStatusField.Value = CommOrderStatusField.Parse(ref msg, CommOrderStatusField.Length);
            state.FilledTotalSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            state.FilledPxField.Value = CommPxField.Parse(ref msg, CommPxField.Length);
            state.FilledSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            state.RemainSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            state.TextField.Value = CommTextField.Parse(ref msg, CommTextField.Length);
            return state;
        }

        public override string ToPlainText()
        {
            return SymbolField.StringValue + ":" + OrderIDField.StringValue + " " + FilledSzField.StringValue + " @ " + FilledPxField.StringValue;
        }
    }

    public class LoginMessage : CommMessage
    {
        public static string Type = "2";
        public static int Length = CommTypeField.Length + CommNameField.Length;
        public CommNameField NameField = new CommNameField();

        public LoginMessage()
        {
            TypeField = new CommTypeField(Type);
        }
        public static string Format(LoginMessage msg)
        {
            return msg.TypeField.StringValue + msg.NameField.StringValue;
        }

        public override string ToPlainText()
        {
            return "Login using " + this.NameField.Value;
        }
    }

    public class LoginStatusMessage : CommMessage
    {
        public static string Type = "3";
        public static int Length = CommTypeField.Length + CommErrorCodeField.Length;

        public CommErrorCodeField ErrorCode = new CommErrorCodeField();

        public LoginStatusMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static bool IsType(string str)
        {
            return str.Length >= Length && str[0] == Type[0];
        }

        public static string Format(LoginStatusMessage msg)
        {
            return msg.TypeField.StringValue + msg.ErrorCode.StringValue;
        }

        public static LoginStatusMessage Parse(ref string msg) {
            LoginStatusMessage state = new LoginStatusMessage();
            state.TypeField.Value = CommTypeField.Parse(ref msg, CommTypeField.Length);
            state.ErrorCode.Value = CommErrorCodeField.Parse(ref msg, CommErrorCodeField.Length);
            return state;
        }

        public Boolean Login()
        {
            return ErrorCode.IntValue == (int)CommErrorCodeField.Code.AllOk;
        }

        public override string ToPlainText()
        {
            if ((int)CommErrorCodeField.Code.AllOk == ErrorCode.IntValue)
            {
                return "Login Ok";
            }
            else
            {
                return "Login Failed";
            }
        }
    }

    public class SubscribeMarketDataMessage : CommMessage
    {
        public static string Type = "4";

        public CommSymbolField SymbolField = new CommSymbolField();
        public CommFlagField FlagField = new CommFlagField();

        public SubscribeMarketDataMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static string Format(SubscribeMarketDataMessage msg)
        {
            return msg.TypeField.StringValue + msg.FlagField.StringValue + msg.SymbolField.StringValue;
        }
    }

    public class SubscribeMarketDataStatusMessage : CommMessage
    {
        public static string Type = "5";
        public static int Length = CommTypeField.Length + CommErrorCodeField.Length + CommInstrumentIndexField.Length + CommSymbolField.Length + CommFlagField.Length;

        public CommErrorCodeField ErrorCode = new CommErrorCodeField();
        public CommInstrumentIndexField InstrumentIndex = new CommInstrumentIndexField();
        public CommSymbolField Symbol = new CommSymbolField();
        public CommFlagField Flag = new CommFlagField();


        public SubscribeMarketDataStatusMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static bool IsType(string str)
        {
            return str.Length >= Length && str[0] == Type[0];
        }

        public static SubscribeMarketDataStatusMessage Parse(ref string msg)
        {
            SubscribeMarketDataStatusMessage state = new SubscribeMarketDataStatusMessage();
            state.TypeField.Value = CommTypeField.Parse(ref msg, CommTypeField.Length);
            state.InstrumentIndex.Value = CommInstrumentIndexField.Parse(ref msg, CommInstrumentIndexField.Length);
            state.Symbol.Value = CommSymbolField.Parse(ref msg, CommSymbolField.Length);
            state.Flag.Value = CommFlagField.Parse(ref msg, CommFlagField.Length);
            state.ErrorCode.Value = CommErrorCodeField.Parse(ref msg, CommErrorCodeField.Length);
            return state;
        }

        public Boolean StatusOk()
        {
            return ErrorCode.IntValue == (int)CommErrorCodeField.Code.AllOk;
        }

        public override string ToPlainText()
        {
            if ((int)CommErrorCodeField.Code.AllOk == ErrorCode.IntValue)
            {
                return "Subscribe Ok";
            }
            else
            {
                return "Subscribe Failed";
            }
        }
    }

    public class MarketDataBestLevelMessage : CommMessage
    {
        public static string Type = "6";
        public static int Length = CommTypeField.Length + CommSymbolField.Length + CommPxField.Length + 
            CommPxField.Length + CommSzField.Length + CommSzField.Length + CommTimestamp.Length;

        public CommSymbolField SymbolField    = new CommSymbolField();
        public CommPxField BestBidPxField = new CommPxField();
        public CommPxField BestAskPxField = new CommPxField();
        public CommSzField BestBidSzField = new CommSzField();
        public CommSzField BestAskSzField = new CommSzField();
        public CommTimestamp TimestampField = new CommTimestamp();

        public MarketDataBestLevelMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static bool IsType(string str)
        {
            return str.Length >= Length && str[0] == Type[0];
        }

        public static MarketDataBestLevelMessage Parse(ref string msg)
        {
            MarketDataBestLevelMessage bidAsk = new MarketDataBestLevelMessage();
            bidAsk.TypeField.Value = CommTypeField.Parse(ref msg, CommTypeField.Length);
            bidAsk.SymbolField.Value = CommSymbolField.Parse(ref msg, CommSymbolField.Length);
            bidAsk.BestBidPxField.Value = CommPxField.Parse(ref msg, CommPxField.Length);
            bidAsk.BestBidSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            bidAsk.BestAskPxField.Value = CommPxField.Parse(ref msg, CommPxField.Length);
            bidAsk.BestAskSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            bidAsk.TimestampField.Value = CommTimestamp.Parse(ref msg, CommTimestamp.Length);
            return bidAsk;
        }

        public override string ToPlainText()
        {
            string msg = TimestampField.StringValue + ":" + SymbolField.StringValue + "-" + BestBidSzField.StringValue + " " +
                            BestBidPxField.StringValue + " ~ " + BestAskPxField.StringValue + " " + BestAskSzField.StringValue;

            return msg;
        }
    }

    public class MarketDataTradeMessage : CommMessage
    {
        public static string Type = "7";
        public static int Length = CommTypeField.Length + CommSymbolField.Length + CommTimestamp.Length + CommPxField.Length + CommSzField.Length + CommSzField.Length;

        public CommSymbolField SymbolField = new CommSymbolField();
        public CommPxField LastPxField = new CommPxField();
        public CommSzField LastSzField = new CommSzField();
        public CommSzField VolumeField = new CommSzField();
        public CommTimestamp TimestampField = new CommTimestamp();

        public MarketDataTradeMessage()
        {
            TypeField = new CommTypeField(Type);
        }

        public static bool IsType(string str)
        {
            return str.Length >= Length && str[0] == Type[0];
        }

        public static MarketDataTradeMessage Parse(ref string msg)
        {
            MarketDataTradeMessage bidAsk = new MarketDataTradeMessage();
            bidAsk.TypeField.Value = CommTypeField.Parse(ref msg, CommTypeField.Length);
            bidAsk.SymbolField.Value = CommSymbolField.Parse(ref msg, CommSymbolField.Length);
            bidAsk.LastPxField.Value = CommPxField.Parse(ref msg, CommPxField.Length);
            bidAsk.LastSzField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            bidAsk.VolumeField.Value = CommSzField.Parse(ref msg, CommSzField.Length);
            bidAsk.TimestampField.Value = CommTimestamp.Parse(ref msg, CommTimestamp.Length);
            return bidAsk;
        }

        public override string ToPlainText()
        {
            string msg = TimestampField.StringValue + ":" + SymbolField.StringValue + "-" + LastPxField.StringValue + " " + LastSzField.StringValue;

            return msg;
        }
    }
}
